#ifndef HASHMAP_H_
#define HASHMAP_H_

#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include "pointers.h"

#define E_OK				0
#define E_NO_ENTRY			-1
#define E_TOO_LONG			-2
#define E_MAP_FULL			-3

#define F_USED				1
#define F_LOCKED			1

#define ALIGNED(n)			(((((n) - 1) >> 2) + 1) << 2)

/* HashMap data structures */

/*	This HashMap is impelemted using Chaining Address method
 *
 * 							Memory Structure
 *	+-------------------------------------------------------------------+
 *	| hashmap_t | unit_t * maxCount | (item_t + maxItemSize) * maxCount |
 *	+-------------------------------------------------------------------+
 */

typedef struct _item_t
{
	uint32_t used;
	uint32_t next;			/* <------- This field and */
	uint32_t keySize;
	uint32_t valueSize;
} item_t;

typedef struct _unit_t
{
	uint32_t count;
	uint32_t offset;		/* <------- this field must be at the same offset */
} unit_t;

typedef struct _hashmap_t
{
	long ref;
	int64_t data;
	uint32_t lock;
	uint32_t items;
	uint32_t stride;
	uint32_t capacity;
} hashmap_t;

typedef void (* enumerator_t)(const void *data, uint32_t length, void *context);

long hashmap_ref(hashmap_t *hashmap);
long hashmap_unref(hashmap_t *hashmap);

void hashmap_wipe(hashmap_t *hashmap);
void hashmap_init(hashmap_t *hashmap, uint32_t capacity, uint32_t itemSpace);

int hashmap_enum(hashmap_t *hashmap, enumerator_t enumerator, void *context);
int hashmap_find(hashmap_t *hashmap, const void *key, uint32_t keySize, enumerator_t enumerator, void *context);
int hashmap_insert(hashmap_t *hashmap, const void *key, uint32_t keySize, const void *value, uint32_t valueSize);
int hashmap_remove(hashmap_t *hashmap, const void *key, uint32_t keySize, enumerator_t enumerator, void *context);

static inline uint32_t hashmap_size(uint32_t capacity, uint32_t itemSpace)
{
	return sizeof(hashmap_t) + (sizeof(unit_t) + sizeof(item_t) + itemSpace) * capacity;
}

#endif /* HASHMAP_H_ */
